/*
 * Copyright (C) 2015-2018 Alibaba Group Holding Limited
 */

#include <mbmaster_api.h>
#include "../pdu/pdu.h"

#if (MBMASTER_CONFIG_READ_HOLDING > 0)
mb_status_t mbmaster_read_holding_reginster(mb_handler_t *req_handler, uint8_t slave_addr, uint16_t start_addr,
                                            uint16_t quantity, uint8_t *respond_buf, uint8_t *respond_count)
{
    mb_status_t status = MB_SUCCESS;

    MB_MUTEX_LOCK(&req_handler->mb_mutex);

    req_handler->slave_addr = slave_addr;
    status = read_holding_reginster_assemble(req_handler, start_addr, quantity);
    if (status != MB_SUCCESS) {
        MB_MUTEX_UNLOCK(&req_handler->mb_mutex);
        return status;
    }

    req_handler->adu_assemble(req_handler);

    status = req_handler->frame_send(req_handler);
    if (status != MB_SUCCESS) {
        MB_MUTEX_UNLOCK(&req_handler->mb_mutex);
        return status;
    }

     /* wait slave respond */
    mb_log(MB_LOG_DEBUG, "waiting for respond\n");

    status = req_handler->frame_recv(req_handler);
    if (status != MB_SUCCESS) {
        MB_MUTEX_UNLOCK(&req_handler->mb_mutex);
        return status;
    }

    status=req_handler->adu_disassemble(req_handler);
	if (status != MB_SUCCESS) {
		MB_MUTEX_UNLOCK(&req_handler->mb_mutex);
		return status;
	}
    status = read_holding_reginster_disassemble(req_handler, respond_buf, respond_count);
    if (status != MB_SUCCESS) {
        MB_MUTEX_UNLOCK(&req_handler->mb_mutex);
        return status;
    }

    MB_MUTEX_UNLOCK(&req_handler->mb_mutex);

    return status;
}


mb_status_t mbmaster_write_holding_reginster(mb_handler_t *req_handler, uint8_t slave_addr, uint16_t start_addr,
											uint16_t quantity, int16_t *buf, uint8_t *respond_buf, uint8_t *respond_count)
{
	mb_status_t status = MB_SUCCESS;

	MB_MUTEX_LOCK(&req_handler->mb_mutex);

	req_handler->slave_addr = slave_addr;
	status = write_holding_reginster_assemble(req_handler, start_addr, quantity, buf);
	if (status != MB_SUCCESS) {
		MB_MUTEX_UNLOCK(&req_handler->mb_mutex);
		return status;
	}

	req_handler->adu_assemble(req_handler);

	status = req_handler->frame_send(req_handler);
	if (status != MB_SUCCESS) {
		MB_MUTEX_UNLOCK(&req_handler->mb_mutex);
		return status;
	}

	 /* wait slave respond */
	mb_log(MB_LOG_DEBUG, "waiting for respond\n");

	status = req_handler->frame_recv(req_handler);
	if (status != MB_SUCCESS) {
		MB_MUTEX_UNLOCK(&req_handler->mb_mutex);
		return status;
	}

	status=req_handler->adu_disassemble(req_handler);
	if (status != MB_SUCCESS) {
		MB_MUTEX_UNLOCK(&req_handler->mb_mutex);
		return status;
	}

	status = write_holding_reginster_disassemble(req_handler, respond_buf, respond_count);
	if (status != MB_SUCCESS) {
		MB_MUTEX_UNLOCK(&req_handler->mb_mutex);
		return status;
	}

	MB_MUTEX_UNLOCK(&req_handler->mb_mutex);

	return status;
}

mb_status_t mbmaster_read_coil_reginster(mb_handler_t *req_handler, uint8_t slave_addr, uint16_t start_addr,
											uint16_t quantity, uint8_t *respond_buf, uint8_t *respond_count)
{
	mb_status_t status = MB_SUCCESS;

	MB_MUTEX_LOCK(&req_handler->mb_mutex);

	req_handler->slave_addr = slave_addr;
	status = read_coil_reginster_assemble(req_handler, start_addr, quantity);
	if (status != MB_SUCCESS) {
		MB_MUTEX_UNLOCK(&req_handler->mb_mutex);
		return status;
	}

	req_handler->adu_assemble(req_handler);

	status = req_handler->frame_send(req_handler);
	if (status != MB_SUCCESS) {
		MB_MUTEX_UNLOCK(&req_handler->mb_mutex);
		return status;
	}

	 /* wait slave respond */
	mb_log(MB_LOG_DEBUG, "waiting for respond\n");

	status = req_handler->frame_recv(req_handler);
	if (status != MB_SUCCESS) {
		MB_MUTEX_UNLOCK(&req_handler->mb_mutex);
		return status;
	}

	status=req_handler->adu_disassemble(req_handler);
	if (status != MB_SUCCESS) {
		MB_MUTEX_UNLOCK(&req_handler->mb_mutex);
		return status;
	}
	status = read_coil_reginster_disassemble(req_handler, respond_buf, respond_count);
	if (status != MB_SUCCESS) {
		MB_MUTEX_UNLOCK(&req_handler->mb_mutex);
		return status;
	}

	MB_MUTEX_UNLOCK(&req_handler->mb_mutex);

	return status;
}


mb_status_t mbmaster_write_coil_reginster(mb_handler_t *req_handler, uint8_t slave_addr, uint16_t start_addr,
																						uint16_t val, uint8_t *respond_buf, uint8_t *respond_count)
{
	mb_status_t status = MB_SUCCESS;

	MB_MUTEX_UNLOCK(&req_handler->mb_mutex);

	req_handler->slave_addr = slave_addr;
	status = write_coil_reginster_assemble(req_handler, start_addr, val);
	if (status != MB_SUCCESS) {
		MB_MUTEX_UNLOCK(&req_handler->mb_mutex);
		return status;
	}

	req_handler->adu_assemble(req_handler);

	status = req_handler->frame_send(req_handler);
	if (status != MB_SUCCESS) {
		MB_MUTEX_UNLOCK(&req_handler->mb_mutex);
		return status;
	}

	 /* wait slave respond */
	mb_log(MB_LOG_DEBUG, "waiting for respond\n");

	status = req_handler->frame_recv(req_handler);
	if (status != MB_SUCCESS) {
		MB_MUTEX_UNLOCK(&req_handler->mb_mutex);
		return status;
	}

	status=req_handler->adu_disassemble(req_handler);
	if (status != MB_SUCCESS) {
		MB_MUTEX_UNLOCK(&req_handler->mb_mutex);
		return status;
	}
	status = write_coil_reginster_disassemble(req_handler, respond_buf, respond_count);
	if (status != MB_SUCCESS) {
		MB_MUTEX_UNLOCK(&req_handler->mb_mutex);
		return status;
	}

	MB_MUTEX_UNLOCK(&req_handler->mb_mutex);

	return status;
}



/*
be in common use modbus write
param:
	req_handler:modbus hander
	slava_id:slave device id
	fun_code:function code
	start_addr:register start address
	w_buf：write buffer
	w_len:write length
	res_buf:recive data
	res_len:recive data length pointer
return:mb_status_t
*/
mb_status_t mbmaster_single_write_reginster(mb_handler_t *req_handler,uint8_t slave_id,uint16_t start_addr,
									uint16_t *w_buf,uint16_t w_len,uint8_t *res_buf,uint8_t *res_len){
	mb_status_t status = MB_SUCCESS;

	MB_MUTEX_LOCK(&req_handler->mb_mutex);
	req_handler->slave_addr = slave_id;
	status=write_single_reginster_assemble(req_handler,start_addr,w_buf,w_len);
	if (status != MB_SUCCESS) {
		MB_MUTEX_UNLOCK(&req_handler->mb_mutex);
		return status;
	}
	req_handler->adu_assemble(req_handler);
	status = req_handler->frame_send(req_handler);
	if (status != MB_SUCCESS) {
		MB_MUTEX_UNLOCK(&req_handler->mb_mutex);
		return status;
	}

	/* wait slave respond */
	mb_log(MB_LOG_DEBUG, "waiting for respond\n");

	status = req_handler->frame_recv(req_handler);
	if (status != MB_SUCCESS) {
		MB_MUTEX_UNLOCK(&req_handler->mb_mutex);
		return status;
	}

	status=req_handler->adu_disassemble(req_handler);
	if (status != MB_SUCCESS) {
		MB_MUTEX_UNLOCK(&req_handler->mb_mutex);
		return status;
	}


	status=write_single_reginster_disassemble(req_handler,res_buf,res_len);
	if (status != MB_SUCCESS) {
		MB_MUTEX_UNLOCK(&req_handler->mb_mutex);
		return status;
	}
	MB_MUTEX_UNLOCK(&req_handler->mb_mutex);
	return status;
}


/*
be in common use read reginster
param:
	req_handler:modbus handler
	fun_code:modbus function code
	slava_id:slave device id 
	start_addr:start address
	read_len:read length
	res_buf:recive read data buffer
	res_len:recove data length
return:
*/
mb_status_t mbmaster_single_read_reginster(mb_handler_t *req_handler,uint8_t slave_id,uint16_t start_addr,
									uint16_t read_len,uint8_t *res_buf,uint8_t *res_len){
	mb_status_t status = MB_SUCCESS;

    MB_MUTEX_LOCK(&req_handler->mb_mutex);

    req_handler->slave_addr = slave_id;
    status = read_single_reginster_assemble(req_handler,start_addr,read_len);
    if (status != MB_SUCCESS) {
        MB_MUTEX_UNLOCK(&req_handler->mb_mutex);
        return status;
    }

    req_handler->adu_assemble(req_handler);

    status = req_handler->frame_send(req_handler);
    if (status != MB_SUCCESS) {
        MB_MUTEX_UNLOCK(&req_handler->mb_mutex);
        return status;
    }

     /* wait slave respond */
    mb_log(MB_LOG_DEBUG, "waiting for respond\n");

    status = req_handler->frame_recv(req_handler);
    if (status != MB_SUCCESS) {
        MB_MUTEX_UNLOCK(&req_handler->mb_mutex);
        return status;
    }

    status=req_handler->adu_disassemble(req_handler);
	if (status != MB_SUCCESS) {
		MB_MUTEX_UNLOCK(&req_handler->mb_mutex);
		return status;
	}


    status = read_single_reginster_disassemble(req_handler,res_buf,res_len);
    if (status != MB_SUCCESS) {
        MB_MUTEX_UNLOCK(&req_handler->mb_mutex);
        return status;
    }

    MB_MUTEX_UNLOCK(&req_handler->mb_mutex);

    return status;
}

#endif /* MBMASTER_CONFIG_READ_HOLDING */
